package config

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"

	"github.com/go-redis/redis/v8"
	"gopkg.in/yaml.v3"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// YamlReader YAML配置文件读取器
type YamlReader struct {
	configPath string
}

// NewYamlReader 创建新的YAML读取器，支持可变参数
func NewYamlReader(configPath ...string) *YamlReader {
	var path string
	if len(configPath) > 0 && configPath[0] != "" {
		path = configPath[0]
	} else {
		path = DefaultConfigPath
	}
	return &YamlReader{
		configPath: path,
	}
}

// ReadConfig 读取YAML配置文件
func (r *YamlReader) ReadConfig(config interface{}) error {
	// 读取文件内容
	data, err := ioutil.ReadFile(r.configPath)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	// 解析YAML
	err = yaml.Unmarshal(data, config)
	if err != nil {
		return fmt.Errorf("解析YAML配置失败: %w", err)
	}

	return nil
}

// ReadConfigFromDir 从指定目录读取配置文件
func (r *YamlReader) ReadConfigFromDir(dir, filename string, config interface{}) error {
	configPath := filepath.Join(dir, filename)
	r.configPath = configPath
	return r.ReadConfig(config)
}

// GetConfigPath 获取当前配置文件路径
func (r *YamlReader) GetConfigPath() string {
	return r.configPath
}

// InstanceFactory 实例工厂
type InstanceFactory struct {
	config *DatabaseConfig
}

// NewInstanceFactory 创建实例工厂
func NewInstanceFactory(config *DatabaseConfig) *InstanceFactory {
	return &InstanceFactory{
		config: config,
	}
}

// CreateMySQLInstance 创建MySQL实例
func (f *InstanceFactory) CreateMySQLInstance(name string) (*gorm.DB, error) {
	conn, exists := f.config.MySQL[name]
	if !exists {
		return nil, fmt.Errorf("MySQL连接配置 '%s' 不存在", name)
	}

	dsn := conn.GetMySQLDSN()
	
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info),
	})
	if err != nil {
		return nil, fmt.Errorf("连接MySQL数据库失败: %w", err)
	}

	// 设置连接池参数
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("获取底层数据库连接失败: %w", err)
	}

	if conn.MaxIdle > 0 {
		sqlDB.SetMaxIdleConns(conn.MaxIdle)
	}
	if conn.MaxOpen > 0 {
		sqlDB.SetMaxOpenConns(conn.MaxOpen)
	}
	sqlDB.SetConnMaxLifetime(time.Hour)

	return db, nil
}

// CreateRedisInstance 创建Redis实例
func (f *InstanceFactory) CreateRedisInstance(name string) (*redis.Client, error) {
	conn, exists := f.config.Redis[name]
	if !exists {
		return nil, fmt.Errorf("Redis连接配置 '%s' 不存在", name)
	}

	poolSize := conn.PoolSize
	if poolSize <= 0 {
		poolSize = 10
	}

	rdb := redis.NewClient(&redis.Options{
		Addr:     conn.GetRedisAddr(),
		Password: conn.Password,
		DB:       conn.DB,
		PoolSize: poolSize,
	})

	return rdb, nil
}

// 默认配置文件路径
const (
	DefaultConfigPath = "config.yaml"
	DefaultConfigDir  = "config"
	DefaultConfigFile = "config.yaml"
)

// LoadYamlConfig 加载YAML配置文件（对外API）
// 支持可变参数：LoadYamlConfig(config) 或 LoadYamlConfig(config, "custom.yaml")
func LoadYamlConfig(config interface{}, configPath ...string) error {
	var path string
	if len(configPath) > 0 && configPath[0] != "" {
		path = configPath[0]
	} else {
		path = DefaultConfigPath
	}
	reader := NewYamlReader(path)
	return reader.ReadConfig(config)
}

// LoadYamlConfigWithDefault 使用默认配置文件加载YAML配置（保持向后兼容）
func LoadYamlConfigWithDefault(config interface{}) error {
	return LoadYamlConfig(config)
}

// LoadYamlConfigFromDir 从目录加载YAML配置文件（对外API）
// 支持可变参数：LoadYamlConfigFromDir(config) 或 LoadYamlConfigFromDir(config, "dir") 或 LoadYamlConfigFromDir(config, "dir", "file.yaml")
func LoadYamlConfigFromDir(config interface{}, params ...string) error {
	var dir, filename string
	
	// 解析可变参数
	if len(params) > 0 && params[0] != "" {
		dir = params[0]
	} else {
		dir = DefaultConfigDir
	}
	
	if len(params) > 1 && params[1] != "" {
		filename = params[1]
	} else {
		filename = DefaultConfigFile
	}
	
	reader := NewYamlReader()
	return reader.ReadConfigFromDir(dir, filename, config)
}

// LoadYamlConfigFromDefaultDir 从默认目录加载默认配置文件（保持向后兼容）
func LoadYamlConfigFromDefaultDir(config interface{}) error {
	return LoadYamlConfigFromDir(config)
}

// CreateMySQLFromConfig 从配置创建MySQL实例（对外API）
func CreateMySQLFromConfig(config *DatabaseConfig, name string) (*gorm.DB, error) {
	factory := NewInstanceFactory(config)
	return factory.CreateMySQLInstance(name)
}

// CreateRedisFromConfig 从配置创建Redis实例（对外API）
func CreateRedisFromConfig(config *DatabaseConfig, name string) (*redis.Client, error) {
	factory := NewInstanceFactory(config)
	return factory.CreateRedisInstance(name)
}

// ConfigReader 通用配置读取器
type ConfigReader struct {
	configData map[string]interface{}
	configPath string
}

// NewConfigReader 创建新的配置读取器
func NewConfigReader(configPath ...string) *ConfigReader {
	var path string
	if len(configPath) > 0 && configPath[0] != "" {
		path = configPath[0]
	} else {
		path = DefaultConfigPath
	}
	return &ConfigReader{
		configPath: path,
	}
}

// LoadConfig 加载配置文件到内存
func (cr *ConfigReader) LoadConfig() error {
	// 读取文件内容
	data, err := ioutil.ReadFile(cr.configPath)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	// 解析YAML到map
	err = yaml.Unmarshal(data, &cr.configData)
	if err != nil {
		return fmt.Errorf("解析YAML配置失败: %w", err)
	}

	return nil
}

// GetString 获取字符串类型的配置值
func (cr *ConfigReader) GetString(key string) (string, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return "", err
		}
	}
	
	value, exists := cr.configData[key]
	if !exists {
		return "", fmt.Errorf("配置项 '%s' 不存在", key)
	}
	
	if str, ok := value.(string); ok {
		return str, nil
	}
	
	return fmt.Sprintf("%v", value), nil
}

// GetInt 获取整数类型的配置值
func (cr *ConfigReader) GetInt(key string) (int, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return 0, err
		}
	}
	
	value, exists := cr.configData[key]
	if !exists {
		return 0, fmt.Errorf("配置项 '%s' 不存在", key)
	}
	
	if intVal, ok := value.(int); ok {
		return intVal, nil
	}
	
	return 0, fmt.Errorf("配置项 '%s' 不是整数类型", key)
}

// GetBool 获取布尔类型的配置值
func (cr *ConfigReader) GetBool(key string) (bool, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return false, err
		}
	}
	
	value, exists := cr.configData[key]
	if !exists {
		return false, fmt.Errorf("配置项 '%s' 不存在", key)
	}
	
	if boolVal, ok := value.(bool); ok {
		return boolVal, nil
	}
	
	return false, fmt.Errorf("配置项 '%s' 不是布尔类型", key)
}

// GetMap 获取映射类型的配置值
func (cr *ConfigReader) GetMap(key string) (map[string]interface{}, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return nil, err
		}
	}
	
	value, exists := cr.configData[key]
	if !exists {
		return nil, fmt.Errorf("配置项 '%s' 不存在", key)
	}
	
	if mapVal, ok := value.(map[string]interface{}); ok {
		return mapVal, nil
	}
	
	// 尝试转换 map[interface{}]interface{} 到 map[string]interface{}
	if interfaceMap, ok := value.(map[interface{}]interface{}); ok {
		result := make(map[string]interface{})
		for k, v := range interfaceMap {
			if strKey, ok := k.(string); ok {
				result[strKey] = v
			}
		}
		return result, nil
	}
	
	return nil, fmt.Errorf("配置项 '%s' 不是映射类型", key)
}

// GetNestedValue 获取嵌套配置值，支持点号分隔的路径，如 "database.mysql.host"
func (cr *ConfigReader) GetNestedValue(path string) (interface{}, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return nil, err
		}
	}
	
	keys := splitPath(path)
	current := cr.configData
	
	for i, key := range keys {
		if i == len(keys)-1 {
			// 最后一个键，返回值
			if value, exists := current[key]; exists {
				return value, nil
			}
			return nil, fmt.Errorf("配置路径 '%s' 不存在", path)
		}
		
		// 中间键，继续向下查找
		if nextLevel, exists := current[key]; exists {
			if nextMap, ok := nextLevel.(map[string]interface{}); ok {
				current = nextMap
			} else if nextInterfaceMap, ok := nextLevel.(map[interface{}]interface{}); ok {
				// 转换 map[interface{}]interface{} 到 map[string]interface{}
				converted := make(map[string]interface{})
				for k, v := range nextInterfaceMap {
					if strKey, ok := k.(string); ok {
						converted[strKey] = v
					}
				}
				current = converted
			} else {
				return nil, fmt.Errorf("配置路径 '%s' 在 '%s' 处不是映射类型", path, key)
			}
		} else {
			return nil, fmt.Errorf("配置路径 '%s' 在 '%s' 处不存在", path, key)
		}
	}
	
	return nil, fmt.Errorf("配置路径 '%s' 不存在", path)
}

// GetNestedString 获取嵌套字符串配置值
func (cr *ConfigReader) GetNestedString(path string) (string, error) {
	value, err := cr.GetNestedValue(path)
	if err != nil {
		return "", err
	}
	
	if str, ok := value.(string); ok {
		return str, nil
	}
	
	return fmt.Sprintf("%v", value), nil
}

// GetNestedInt 获取嵌套整数配置值
func (cr *ConfigReader) GetNestedInt(path string) (int, error) {
	value, err := cr.GetNestedValue(path)
	if err != nil {
		return 0, err
	}
	
	if intVal, ok := value.(int); ok {
		return intVal, nil
	}
	
	return 0, fmt.Errorf("配置路径 '%s' 不是整数类型", path)
}

// GetAllConfig 获取所有配置数据
func (cr *ConfigReader) GetAllConfig() (map[string]interface{}, error) {
	if cr.configData == nil {
		if err := cr.LoadConfig(); err != nil {
			return nil, err
		}
	}
	
	return cr.configData, nil
}

// splitPath 分割配置路径
func splitPath(path string) []string {
	if path == "" {
		return []string{}
	}
	
	var result []string
	var current string
	
	for _, char := range path {
		if char == '.' {
			if current != "" {
				result = append(result, current)
				current = ""
			}
		} else {
			current += string(char)
		}
	}
	
	if current != "" {
		result = append(result, current)
	}
	
	return result
}

// LoadConfigFile 加载配置文件（对外API）
// 支持可变参数：LoadConfigFile() 或 LoadConfigFile("custom.yaml")
func LoadConfigFile(configPath ...string) (*ConfigReader, error) {
	reader := NewConfigReader(configPath...)
	err := reader.LoadConfig()
	if err != nil {
		return nil, err
	}
	return reader, nil
}

// GetConfigValue 直接获取配置值（对外API）
// 支持嵌套路径，如 "database.mysql.host"
func GetConfigValue(path string, configPath ...string) (interface{}, error) {
	reader := NewConfigReader(configPath...)
	return reader.GetNestedValue(path)
}

// GetConfigString 直接获取字符串配置值（对外API）
func GetConfigString(path string, configPath ...string) (string, error) {
	reader := NewConfigReader(configPath...)
	return reader.GetNestedString(path)
}

// GetConfigInt 直接获取整数配置值（对外API）
func GetConfigInt(path string, configPath ...string) (int, error) {
	reader := NewConfigReader(configPath...)
	return reader.GetNestedInt(path)
}

// DatabaseConfig 数据库配置结构（临时定义，如果其他地方已定义可删除）
type DatabaseConfig struct {
	MySQL map[string]*MySQLConfig `yaml:"mysql"`
	Redis map[string]*RedisConfig `yaml:"redis"`
}

// MySQLConfig MySQL配置
type MySQLConfig struct {
	Host     string `yaml:"host"`
	Port     int    `yaml:"port"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	Database string `yaml:"database"`
	Charset  string `yaml:"charset"`
	MaxIdle  int    `yaml:"max_idle"`
	MaxOpen  int    `yaml:"max_open"`
}

// GetMySQLDSN 获取MySQL DSN
func (c *MySQLConfig) GetMySQLDSN() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local",
		c.Username, c.Password, c.Host, c.Port, c.Database, c.Charset)
}

// RedisConfig Redis配置
type RedisConfig struct {
	Host     string `yaml:"host"`
	Port     int    `yaml:"port"`
	Password string `yaml:"password"`
	DB       int    `yaml:"db"`
	PoolSize int    `yaml:"pool_size"`
}

// GetRedisAddr 获取Redis地址
func (c *RedisConfig) GetRedisAddr() string {
	return fmt.Sprintf("%s:%d", c.Host, c.Port)
}